// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © finallynitin
//credits to ajithcpas
//modified from "CPR (Central Pivot Range)" script by ajithcpas https://www.tradingview.com/v/R6lRetr0/


//@version=6
indicator('Simple CPR for intraday index trading', shorttitle = 'Simple CPR', overlay = true, max_lines_count = 500, max_labels_count = 500)

AUTO = 'Auto'
DAILY = 'Daily'
WEEKLY = 'Weekly'
MONTHLY = 'Monthly'
QUARTERLY = 'Quarterly'
HALF_YEARLY = 'Half-yearly'
YEARLY = 'Yearly'

TRADITIONAL = 'Traditional'
FIBONACCI = 'Fibonacci'
CLASSIC = 'Classic'
CAMARILLA = 'Camarilla'

// Input fields
kind = input.string(title = 'Type', defval = 'Traditional', options = [TRADITIONAL, FIBONACCI, CLASSIC, CAMARILLA])
cpr_time_frame = input.string(title = 'CPR Timeframe', defval = AUTO, options = [AUTO, DAILY, WEEKLY, MONTHLY, QUARTERLY, HALF_YEARLY, YEARLY])
look_back = input.int(title = 'Number of CPR Back', defval = 1, minval = 1, maxval = 5000)
position_labels = input.string('Right', 'Labels Position', options = ['Left', 'Right'])
line_width = input.int(title = 'Line Width', defval = 3, minval = 1, maxval = 100)
hist_sr_show = input.bool(true, 'Show Historical SR Pivots')
is_daily_based = input.bool(title = 'Use Daily-based Values', defval = true, tooltip = 'When this option is unchecked, CPR will use intraday data while calculating on intraday charts. If Extended Hours are displayed on the chart, they will be taken into account during the CPR level calculation. If intraday OHLC values are different from daily-based values (normal for stocks), the CPR levels will also differ.')

// Variables
var arr_time = array.new_int()
var p = array.new_float()
var tp = array.new_float()
var bp = array.new_float()
var SR_COLOR = #FB8C00
var DEV_SR_COLOR = #E2BEE7
var pdh_arr = array.new_float()
var pdl_arr = array.new_float()

// Daily previous-day series
pdHighSer = request.security(syminfo.tickerid, 'D', high[1],  lookahead = barmerge.lookahead_on)
pdLowSer  = request.security(syminfo.tickerid, 'D', low[1],   lookahead = barmerge.lookahead_on)

//CPR Customisation
cpr_show = input.bool(true, '', inline = 'CPR', group = 'CPR Customisation')
cpr_color = input.color(color.blue, 'Show CPR', inline = 'CPR', group = 'CPR Customisation')
cpr_show_lines = input.bool(true, 'Show CPR Lines', group = 'CPR Customisation')
cpr_show_fill = input.bool(false, 'Show CPR Fill', group = 'CPR Customisation')
cpr_show_prices = input.bool(false, 'Show CPR Price', group = 'CPR Customisation')
cpr_show_labels = input.bool(false, 'Show CPR Label', group = 'CPR Customisation')
cpr_line_style = input.string('Dotted', 'CPR Line Style', options = ['Solid', 'Dashed', 'Dotted'], group = 'CPR Customisation')

//Pivot Customisation
sr_show = input.bool(true, 'Show SR Levels', inline = 'Show SR Pivots', group = 'Pivot Customisation')
sr_show_labels = input.bool(true, 'Show SR Label', group = 'Pivot Customisation')
sr_show_prices = input.bool(true, 'Show SR Price', group = 'Pivot Customisation')


//Pivots
var r0_5 = array.new_float()
var s0_5 = array.new_float()
s0_5_show = input.bool(false, '', inline = 'S0.5/R0.5', group = 'Pivot Display')
s0_5_color = input.color(SR_COLOR, 'S0.5', inline = 'S0.5/R0.5', group = 'Pivot Display')
r0_5_show = input.bool(false, '', inline = 'S0.5/R0.5', group = 'Pivot Display')
r0_5_color = input.color(SR_COLOR, 'R0.5', inline = 'S0.5/R0.5', group = 'Pivot Display')
var r1 = array.new_float()
var s1 = array.new_float()
s1_show = input.bool(true, '', inline = 'S1/R1', group = 'Pivot Display')
s1_color = input.color(SR_COLOR, 'S1', inline = 'S1/R1', group = 'Pivot Display')
r1_show = input.bool(true, '', inline = 'S1/R1', group = 'Pivot Display')
r1_color = input.color(SR_COLOR, 'R1', inline = 'S1/R1', group = 'Pivot Display')
var r1_5 = array.new_float()
var s1_5 = array.new_float()
s1_5_show = input.bool(false, '', inline = 'S1.5/R1.5', group = 'Pivot Display')
s1_5_color = input.color(SR_COLOR, 'S1.5', inline = 'S1.5/R1.5', group = 'Pivot Display')
r1_5_show = input.bool(false, '', inline = 'S1.5/R1.5', group = 'Pivot Display')
r1_5_color = input.color(SR_COLOR, 'R1.5', inline = 'S1.5/R1.5', group = 'Pivot Display')
var r2 = array.new_float()
var s2 = array.new_float()
s2_show = input.bool(false, '', inline = 'S2/R2', group = 'Pivot Display')
s2_color = input.color(SR_COLOR, 'S2', inline = 'S2/R2', group = 'Pivot Display')
r2_show = input.bool(false, '', inline = 'S2/R2', group = 'Pivot Display')
r2_color = input.color(SR_COLOR, 'R2', inline = 'S2/R2', group = 'Pivot Display')
var r2_5 = array.new_float()
var s2_5 = array.new_float()
s2_5_show = input.bool(false, '', inline = 'S2.5/R2.5', group = 'Pivot Display')
s2_5_color = input.color(SR_COLOR, 'S2.5', inline = 'S2.5/R2.5', group = 'Pivot Display')
r2_5_show = input.bool(false, '', inline = 'S2.5/R2.5', group = 'Pivot Display')
r2_5_color = input.color(SR_COLOR, 'R2.5', inline = 'S2.5/R2.5', group = 'Pivot Display')
var r3 = array.new_float()
var s3 = array.new_float()
s3_show = input.bool(false, '', inline = 'S3/R3', group = 'Pivot Display')
s3_color = input.color(SR_COLOR, 'S3', inline = 'S3/R3', group = 'Pivot Display')
r3_show = input.bool(false, '', inline = 'S3/R3', group = 'Pivot Display')
r3_color = input.color(SR_COLOR, 'R3', inline = 'S3/R3', group = 'Pivot Display')
var r3_5 = array.new_float()
var s3_5 = array.new_float()
s3_5_show = input.bool(false, '', inline = 'S3.5/R3.5', group = 'Pivot Display')
s3_5_color = input.color(SR_COLOR, 'S3.5', inline = 'S3.5/R3.5', group = 'Pivot Display')
r3_5_show = input.bool(false, '', inline = 'S3.5/R3.5', group = 'Pivot Display')
r3_5_color = input.color(SR_COLOR, 'R3.5', inline = 'S3.5/R3.5', group = 'Pivot Display')
var r4 = array.new_float()
var s4 = array.new_float()
s4_show = input.bool(false, '', inline = 'S4/R4', group = 'Pivot Display')
s4_color = input.color(SR_COLOR, 'S4', inline = 'S4/R4', group = 'Pivot Display')
r4_show = input.bool(false, '', inline = 'S4/R4', group = 'Pivot Display')
r4_color = input.color(SR_COLOR, 'R4', inline = 'S4/R4', group = 'Pivot Display')
var r4_5 = array.new_float()
var s4_5 = array.new_float()
s4_5_show = input.bool(false, '', inline = 'S4.5/R4.5', group = 'Pivot Display')
s4_5_color = input.color(SR_COLOR, 'S4.5', inline = 'S4.5/R4.5', group = 'Pivot Display')
r4_5_show = input.bool(false, '', inline = 'S4.5/R4.5', group = 'Pivot Display')
r4_5_color = input.color(SR_COLOR, 'R4.5', inline = 'S4.5/R4.5', group = 'Pivot Display')
var r5 = array.new_float()
var s5 = array.new_float()
s5_show = input.bool(false, '', inline = 'S5/R5', group = 'Pivot Display')
s5_color = input.color(SR_COLOR, 'S5', inline = 'S5/R5', group = 'Pivot Display')
r5_show = input.bool(false, '', inline = 'S5/R5', group = 'Pivot Display')
r5_color = input.color(SR_COLOR, 'R5', inline = 'S5/R5', group = 'Pivot Display')

//Developing CPR
dev_cpr_show = input.bool(false, '', inline = 'Dev CPR', group = 'Developing CPR levels')
dev_cpr_color = input.color(DEV_SR_COLOR, 'Dev CPR', inline = 'Dev CPR', group = 'Developing CPR levels')
var dev_r1 = array.new_float()
var dev_s1 = array.new_float()
dev_s1_show = input.bool(false, '', inline = 'S1/R1', group = 'Developing CPR levels')
dev_s1_color = input.color(DEV_SR_COLOR, 'S1', inline = 'S1/R1', group = 'Developing CPR levels')
dev_r1_show = input.bool(false, '', inline = 'S1/R1', group = 'Developing CPR levels')
dev_r1_color = input.color(DEV_SR_COLOR, 'R1', inline = 'S1/R1', group = 'Developing CPR levels')
extend_dev_cpr_line = input.bool(false, '', inline = 'extend', group = 'Developing CPR levels')

dev_cpr_show_labels = input.bool(true, 'Show Dev CPR Labels', group = 'Developing CPR levels')
dev_cpr_show_prices = input.bool(false, 'Show Dev CPR Price Levels', group = 'Developing CPR levels')
dev_r1_show_labels = input.bool(true, 'Show Dev R1 Labels', group = 'Developing CPR levels')
dev_r1_show_prices = input.bool(false, 'Show Dev R1 Price Levels', group = 'Developing CPR levels')
dev_s1_show_labels = input.bool(true, 'Show Dev S1 Labels', group = 'Developing CPR levels')
dev_s1_show_prices = input.bool(false, 'Show Dev S1 Price Levels', group = 'Developing CPR levels')

// — Group for CPR↔SR fill —
fill_cpr_r1     = input.bool(false,    'Fill CPR → R1',        group='Pivot Customisation')
fill_cpr_r1_col = input.color(color.new(color.orange, 75), 'CPR–R1 Fill Color',    group='Pivot Customisation')
fill_cpr_s1     = input.bool(false,    'Fill CPR → S1',        group='Pivot Customisation')
fill_cpr_s1_col = input.color(color.new(color.orange, 75), 'CPR–S1 Fill Color',    group='Pivot Customisation')


dev_cpr_line_days = input.int(title = 'Extend line by days', defval = 1, minval = 1, maxval = 10, inline = 'extend', group = 'Developing CPR levels', tooltip = 'Enable this when the Dev CPR lines are not visible(i.e. there is a trading holiday in upcoming session).')
check_holidays = input.bool(true, 'Check NSE/BSE holidays', group = 'Developing CPR levels', tooltip = 'Enable this when the Dev CPR lines are not visible(i.e. there is a trading holiday in upcoming session).')


// --- Session Display Toggles ---
show_day = input.bool(false, title = 'Show Previous High/Low', group = 'Session High Low')
session_hl_line_style = input.string(defval = 'Solid', title = 'Line Style', options = ['Solid', 'Dotted', 'Dashed'], group = 'Session High Low')
show_day_open = input.bool(defval = false, title = 'Show Current Day', group = 'Session Open')
session_high_color = input.color(defval = color.aqua , title = 'High Line Color', group = 'Session High Low')
session_low_color = input.color(defval = color.aqua, title = 'Low Line Color', group = 'Session High Low')
session_open_color = input.color(defval = color.aqua, title = 'Line Color', group = 'Session Open')
session_open_line_style = input.string(defval = 'Dashed', title = 'Line Style', options = ['Solid', 'Dotted', 'Dashed'], group = 'Session Open')

// --- PDH/PDL label/price toggles ---
pd_show_labels = input.bool(true,  'Show PH/PL Labels', group='Session High Low')
pd_show_prices = input.bool(true,  'Show PH/PL Prices', group='Session High Low')


//Code
pivotX_open = float(na)
pivotX_open := nz(pivotX_open[1], open)
pivotX_high = float(na)
pivotX_high := nz(pivotX_high[1], high)
pivotX_low = float(na)
pivotX_low := nz(pivotX_low[1], low)
pivotX_prev_open = float(na)
pivotX_prev_open := nz(pivotX_prev_open[1])
pivotX_prev_high = float(na)
pivotX_prev_high := nz(pivotX_prev_high[1])
pivotX_prev_low = float(na)
pivotX_prev_low := nz(pivotX_prev_low[1])
pivotX_prev_close = float(na)
pivotX_prev_close := nz(pivotX_prev_close[1])

get_pivot_resolution() =>
    resolution = 'M'
    if cpr_time_frame == AUTO
        if timeframe.isintraday
            resolution := timeframe.multiplier <= 15 ? 'D' : 'W'
            resolution
        else if timeframe.isdaily
            resolution := 'M'
            resolution
        else if timeframe.isweekly
            resolution := '6M'
            resolution
        else
            resolution := '12M'
            resolution
    else if cpr_time_frame == DAILY
        resolution := 'D'
        resolution
    else if cpr_time_frame == WEEKLY
        resolution := 'W'
        resolution
    else if cpr_time_frame == MONTHLY
        resolution := 'M'
        resolution
    else if cpr_time_frame == QUARTERLY
        resolution := '3M'
        resolution
    else if cpr_time_frame == HALF_YEARLY
        resolution := '6M'
        resolution
    else if cpr_time_frame == YEARLY
        resolution := '12M'
        resolution
    resolution

var lines = array.new_line()
var labels = array.new_label()

draw_line(i, pivot, col, line_style = line.style_solid) =>
    line aLine = na
    if array.size(arr_time) > 1
        aLine := line.new(array.get(arr_time, i), array.get(pivot, i), array.get(arr_time, i + 1), array.get(pivot, i), color = col, xloc = xloc.bar_time, width = line_width, style = line_style)
        array.push(lines, aLine)
    aLine

//Modify draw_label to accept flags and use the right toggles
//Accepts two extra booleans for CPR vs. SR
draw_label(i, y, txt, txt_color, is_cpr = false, is_sr = false) =>
    _showLbl = is_cpr ? cpr_show_labels : is_sr ? sr_show_labels : true
    _showPrc = is_cpr ? cpr_show_prices : is_sr ? sr_show_prices : true
    if _showLbl or _showPrc
        display = ''
        if _showLbl and _showPrc and txt != ''
            display := str.format('                                {0} - {1}', txt, math.round_to_mintick(y))
            display
        else if _showLbl and txt != ''
            display := '                           ' + txt
            display
        else
            display := str.format('                                {0}', math.round_to_mintick(y))
            display
        x = position_labels == 'Left' ? array.get(arr_time, i) : array.get(arr_time, i + 1)
        array.push(labels, label.new(x = x, y = y, text = display, textcolor = txt_color, style = label.style_none, color = #00000000, xloc = xloc.bar_time))


pd_label_text(_name, _price, _showLbl, _showPrc) =>
    // returns the padded label string (or '' if nothing to show)
    txt = ''
    if _showLbl and _showPrc
        txt := str.format('                                {0} - {1}', _name, math.round_to_mintick(_price))
    else if _showLbl
        txt := '                                ' + _name
    else if _showPrc
        txt := str.format('                                {0}', math.round_to_mintick(_price))
    txt


traditional() =>
    pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3

    _r1 = pivotX_Median * 2 - pivotX_prev_low
    _s1 = pivotX_Median * 2 - pivotX_prev_high
    _r2 = pivotX_Median + 1 * (pivotX_prev_high - pivotX_prev_low)
    _s2 = pivotX_Median - 1 * (pivotX_prev_high - pivotX_prev_low)
    //_r3 = pivotX_Median * 2 + (pivotX_prev_high - 2 * pivotX_prev_low)
    _r3 = _r1 + pivotX_prev_high - pivotX_prev_low
    //_s3 = pivotX_Median * 2 - (2 * pivotX_prev_high - pivotX_prev_low)
    _s3 = _s1 - pivotX_prev_high + pivotX_prev_low
    //_r4 = pivotX_Median * 3 + (pivotX_prev_high - 3 * pivotX_prev_low)
    _r4 = _r3 + _r2 - _r1
    //_s4 = pivotX_Median * 3 - (3 * pivotX_prev_high - pivotX_prev_low)
    _s4 = _s3 + _s2 - _s1
    //_r5 = pivotX_Median * 4 + (pivotX_prev_high - 4 * pivotX_prev_low)
    _r5 = _r4 + _r3 - _r2
    //_s5 = pivotX_Median * 4 - (4 * pivotX_prev_high - pivotX_prev_low)
    _s5 = _s4 + _s3 - _s2
    array.push(r0_5, (pivotX_Median + _r1) / 2)
    array.push(s0_5, (pivotX_Median + _s1) / 2)
    array.push(r1, _r1)
    array.push(s1, _s1)
    array.push(r1_5, (_r1 + _r2) / 2)
    array.push(s1_5, (_s1 + _s2) / 2)
    array.push(r2, _r2)
    array.push(s2, _s2)
    array.push(r2_5, (_r2 + _r3) / 2)
    array.push(s2_5, (_s2 + _s3) / 2)
    array.push(r3, _r3)
    array.push(s3, _s3)
    array.push(r3_5, (_r3 + _r4) / 2)
    array.push(s3_5, (_s3 + _s4) / 2)
    array.push(r4, _r4)
    array.push(s4, _s4)
    array.push(r4_5, (_r4 + _r5) / 2)
    array.push(s4_5, (_s4 + _s5) / 2)
    array.push(r5, _r5)
    array.push(s5, _s5)

fibonacci() =>
    pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
    pivot_range = pivotX_prev_high - pivotX_prev_low

    array.push(r1, pivotX_Median + 0.382 * pivot_range)
    array.push(s1, pivotX_Median - 0.382 * pivot_range)
    array.push(r2, pivotX_Median + 0.618 * pivot_range)
    array.push(s2, pivotX_Median - 0.618 * pivot_range)
    array.push(r3, pivotX_Median + 1 * pivot_range)
    array.push(s3, pivotX_Median - 1 * pivot_range)

classic() =>
    pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
    pivot_range = pivotX_prev_high - pivotX_prev_low

    array.push(r1, pivotX_Median * 2 - pivotX_prev_low)
    array.push(s1, pivotX_Median * 2 - pivotX_prev_high)
    array.push(r2, pivotX_Median + 1 * pivot_range)
    array.push(s2, pivotX_Median - 1 * pivot_range)
    array.push(r3, pivotX_Median + 2 * pivot_range)
    array.push(s3, pivotX_Median - 2 * pivot_range)
    array.push(r4, pivotX_Median + 3 * pivot_range)
    array.push(s4, pivotX_Median - 3 * pivot_range)

camarilla() =>
    pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
    pivot_range = pivotX_prev_high - pivotX_prev_low

    array.push(r1, pivotX_prev_close + pivot_range * 1.1 / 12.0)
    array.push(s1, pivotX_prev_close - pivot_range * 1.1 / 12.0)
    array.push(r2, pivotX_prev_close + pivot_range * 1.1 / 6.0)
    array.push(s2, pivotX_prev_close - pivot_range * 1.1 / 6.0)
    array.push(r3, pivotX_prev_close + pivot_range * 1.1 / 4.0)
    array.push(s3, pivotX_prev_close - pivot_range * 1.1 / 4.0)
    array.push(r4, pivotX_prev_close + pivot_range * 1.1 / 2.0)
    array.push(s4, pivotX_prev_close - pivot_range * 1.1 / 2.0)
    r5_val = pivotX_prev_high / pivotX_prev_low * pivotX_prev_close
    array.push(r5, r5_val)
    array.push(s5, 2 * pivotX_prev_close - r5_val)

calc_pivot() =>
    pivotX_Median = (pivotX_prev_high + pivotX_prev_low + pivotX_prev_close) / 3
    pivotX_Bottom = (pivotX_prev_high + pivotX_prev_low) / 2
    pivotX_Top = pivotX_Median * 2 - pivotX_Bottom

    if pivotX_Bottom > pivotX_Top
        temp = pivotX_Bottom
        pivotX_Bottom := pivotX_Top
        pivotX_Top := temp
        pivotX_Top

    array.push(p, pivotX_Median)
    array.push(tp, pivotX_Top)
    array.push(bp, pivotX_Bottom)
    // Capture the prev-day H/L for this CPR segment
    array.push(pdh_arr, pdHighSer)
    array.push(pdl_arr, pdLowSer)


    if kind == TRADITIONAL
        traditional()
    else if kind == FIBONACCI
        fibonacci()
    else if kind == CLASSIC
        classic()
    else if kind == CAMARILLA
        camarilla()

resolution = get_pivot_resolution()

calc_high(prev, curr) =>
    if na(prev) or na(curr)
        nz(prev, nz(curr, na))
    else
        math.max(prev, curr)

calc_low(prev, curr) =>
    if not na(prev) and not na(curr)
        math.min(prev, curr)
    else
        nz(prev, nz(curr, na))

[sec_open, sec_high, sec_low, prev_sec_open, prev_sec_high, prev_sec_low, prev_sec_close, prev_sec_time] = request.security(syminfo.tickerid, resolution, [open, high, low, open[1], high[1], low[1], close[1], time[1]], lookahead = barmerge.lookahead_on)
sec_open_gaps_on = request.security(syminfo.tickerid, resolution, open, gaps = barmerge.gaps_on, lookahead = barmerge.lookahead_on)

var is_change = false
var uses_current_bar = false
var change_time = int(na)
is_time_change = ta.change(time(resolution)) != 0
if is_time_change
    change_time := time
    change_time

var start_time = time

without_time_change = barstate.islast and array.size(arr_time) == 0
is_can_calc_pivot = not uses_current_bar and is_time_change or uses_current_bar and not na(sec_open_gaps_on) or without_time_change
enough_bars_for_calculate = prev_sec_time >= start_time or is_daily_based

if is_can_calc_pivot and enough_bars_for_calculate
    if array.size(arr_time) == 0 and is_daily_based
        pivotX_prev_open := prev_sec_open[1]
        pivotX_prev_high := prev_sec_high[1]
        pivotX_prev_low := prev_sec_low[1]
        pivotX_prev_close := prev_sec_close[1]
        pivotX_open := sec_open[1]
        pivotX_high := sec_high[1]
        pivotX_low := sec_low[1]
        array.push(arr_time, start_time)
        calc_pivot()

    if is_daily_based
        pivotX_prev_open := prev_sec_open
        pivotX_prev_high := prev_sec_high
        pivotX_prev_low := prev_sec_low
        pivotX_prev_close := prev_sec_close
        pivotX_open := sec_open
        pivotX_high := sec_high
        pivotX_low := sec_low
        pivotX_low
    else
        pivotX_prev_high := pivotX_high
        pivotX_prev_low := pivotX_low
        pivotX_prev_open := pivotX_open
        pivotX_prev_close := close[1]
        pivotX_open := open
        pivotX_high := high
        pivotX_low := low
        pivotX_low

    if barstate.islast and not is_change and array.size(arr_time) > 0 and not without_time_change
        array.set(arr_time, array.size(arr_time) - 1, change_time)
    else if without_time_change
        array.push(arr_time, start_time)
    else
        array.push(arr_time, nz(change_time, time))

    calc_pivot()

    if array.size(arr_time) > look_back
        if array.size(arr_time) > 0
            array.shift(arr_time)
        if array.size(p) > 0 and cpr_show
            array.shift(p)
        if array.size(tp) > 0 and cpr_show
            array.shift(tp)
        if array.size(bp) > 0 and cpr_show
            array.shift(bp)
        if array.size(pdh_arr) > 0
            array.shift(pdh_arr)
        if array.size(pdl_arr) > 0
            array.shift(pdl_arr)


        if sr_show or hist_sr_show
            if array.size(r0_5) > 0 and r0_5_show
                array.shift(r0_5)
            if array.size(s0_5) > 0 and s0_5_show
                array.shift(s0_5)
            if array.size(r1) > 0 and r1_show
                array.shift(r1)
            if array.size(s1) > 0 and s1_show
                array.shift(s1)
            if array.size(r1_5) > 0 and r1_5_show
                array.shift(r1_5)
            if array.size(s1_5) > 0 and s1_5_show
                array.shift(s1_5)
            if array.size(r2) > 0 and r2_show
                array.shift(r2)
            if array.size(s2) > 0 and s2_show
                array.shift(s2)
            if array.size(r2_5) > 0 and r2_5_show
                array.shift(r2_5)
            if array.size(s2_5) > 0 and s2_5_show
                array.shift(s2_5)
            if array.size(r3) > 0 and r3_show
                array.shift(r3)
            if array.size(s3) > 0 and s3_show
                array.shift(s3)
            if array.size(r3_5) > 0 and r3_5_show
                array.shift(r3_5)
            if array.size(s3_5) > 0 and s3_5_show
                array.shift(s3_5)
            if array.size(r4) > 0 and r4_show
                array.shift(r4)
            if array.size(s4) > 0 and s4_show
                array.shift(s4)
            if array.size(r4_5) > 0 and r4_5_show
                array.shift(r4_5)
            if array.size(s4_5) > 0 and s4_5_show
                array.shift(s4_5)
            if array.size(r5) > 0 and r5_show
                array.shift(r5)
            if array.size(s5) > 0 and s5_show
                array.shift(s5)
    is_change := true
    is_change
else if not is_daily_based
    pivotX_high := math.max(pivotX_high, high)
    pivotX_low := math.min(pivotX_low, low)
    pivotX_low

if barstate.islast and not is_daily_based and array.size(arr_time) == 0
    runtime.error('Not enough intraday data to calculate CPR. Lower the CPR Timeframe or turn on the \'Use Daily-based Values\' option in the indicator settings.')

if barstate.islast and array.size(arr_time) > 0 and is_change
    is_change := false
    array.push(arr_time, time_close(resolution))

    for idx = 0 to array.size(lines) - 1 by 1
        if array.size(lines) > 0
            line.delete(array.shift(lines))
        if array.size(labels) > 0
            label.delete(array.shift(labels))

    line cpLine = na
    line r1Line = na
    line s1Line = na

    j = array.size(arr_time) - 2

    for idx = 0 to j by 1
        style_cpr = cpr_line_style == 'Solid'  ? line.style_solid : cpr_line_style == 'Dashed' ? line.style_dashed : line.style_dotted

        if array.size(p) > 0 and cpr_show
            cpLine := draw_line(idx, p, cpr_show_lines ? cpr_color : color.new(cpr_color, 100), style_cpr)

        line tp_line = na
        line bp_line = na
        if array.size(tp) > 0 and array.size(bp) > 0 and cpr_show
            tp_line := draw_line(idx, tp, cpr_show_lines ? cpr_color : color.new(cpr_color, 100), style_cpr)
            bp_line := draw_line(idx, bp, cpr_show_lines ? cpr_color : color.new(cpr_color, 100), style_cpr)
            if cpr_show_fill
                linefill.new(tp_line, bp_line, color.new(cpr_color, 70))

        // — draw R1 & S1 on the last bar and remember handles —
        if idx == j and sr_show
            if r1_show
                r1Line := draw_line(idx, r1, r1_color)
                draw_label(idx, array.get(r1, idx), 'R1', r1_color, false, true)
            if s1_show
                s1Line := draw_line(idx, s1, s1_color)
                draw_label(idx, array.get(s1, idx), 'S1', s1_color, false, true)

        // — fills between CPR middle-line and R1/S1 —
        if idx == j and cpr_show
            if fill_cpr_r1 and not na(cpLine) and not na(r1Line)
                linefill.new(cpLine, r1Line, fill_cpr_r1_col)
            if fill_cpr_s1 and not na(cpLine) and not na(s1Line)
                linefill.new(cpLine, s1Line, fill_cpr_r1_col)



// --- draw SR levels ---

    for idx = 0 to j by 1
        if hist_sr_show and idx < j or sr_show and idx == j
            // R0.5 / S0.5
            if r0_5_show
                draw_line(idx, r0_5, r0_5_color, line.style_dashed)
                draw_label(idx, array.get(r0_5, idx), 'R0.5', r0_5_color, false, true)
            if s0_5_show
                draw_line(idx, s0_5, s0_5_color, line.style_dashed)
                draw_label(idx, array.get(s0_5, idx), 'S0.5', s0_5_color, false, true)



            if r1_show
                draw_line(idx, r1, r1_color)
                r1lvl = array.get(r1, idx)
                pct = (r1lvl - close) / close * 100
                pctStr = str.tostring(pct, '#.0')
                displayR1 = str.format('                                          R1 - {0} ({1}%)', math.round_to_mintick(r1lvl), pctStr)
                xR1 = position_labels == 'Left' ? array.get(arr_time, idx) : array.get(arr_time, idx + 1)
                draw_label(idx, array.get(r1, idx), "R1", r1_color, false, true)

            if s1_show
                draw_line(idx, s1, s1_color)
                s1lvl = array.get(s1, idx)
                displayS1 = str.format('                                S1 - {0}', math.round_to_mintick(s1lvl))
                xS1 = position_labels == 'Left' ? array.get(arr_time, idx) : array.get(arr_time, idx + 1)
                draw_label(idx, array.get(s1, idx), "S1", s1_color, false, true)

            // R1.5 / S1.5
            if r1_5_show
                draw_line(idx, r1_5, r1_5_color, line.style_dashed)
                draw_label(idx, array.get(r1_5, idx), 'R1.5', r1_5_color, false, true)
            if s1_5_show
                draw_line(idx, s1_5, s1_5_color, line.style_dashed)
                draw_label(idx, array.get(s1_5, idx), 'S1.5', s1_5_color, false, true)

            // R2 / S2
            if r2_show
                draw_line(idx, r2, r2_color)
                draw_label(idx, array.get(r2, idx), 'R2', r2_color, false, true)
            if s2_show
                draw_line(idx, s2, s2_color)
                draw_label(idx, array.get(s2, idx), 'S2', s2_color, false, true)

            // R2.5 / S2.5
            if r2_5_show
                draw_line(idx, r2_5, r2_5_color, line.style_dashed)
                draw_label(idx, array.get(r2_5, idx), 'R2.5', r2_5_color, false, true)
            if s2_5_show
                draw_line(idx, s2_5, s2_5_color, line.style_dashed)
                draw_label(idx, array.get(s2_5, idx), 'S2.5', s2_5_color, false, true)

            // R3 / S3
            if r3_show
                draw_line(idx, r3, r3_color)
                draw_label(idx, array.get(r3, idx), 'R3', r3_color, false, true)
            if s3_show
                draw_line(idx, s3, s3_color)
                draw_label(idx, array.get(s3, idx), 'S3', s3_color, false, true)

            // R3.5 / S3.5
            if r3_5_show
                draw_line(idx, r3_5, r3_5_color, line.style_dashed)
                draw_label(idx, array.get(r3_5, idx), 'R3.5', r3_5_color, false, true)
            if s3_5_show
                draw_line(idx, s3_5, s3_5_color, line.style_dashed)
                draw_label(idx, array.get(s3_5, idx), 'S3.5', s3_5_color, false, true)

            // R4 / S4
            if r4_show
                draw_line(idx, r4, r4_color)
                draw_label(idx, array.get(r4, idx), 'R4', r4_color, false, true)
            if s4_show
                draw_line(idx, s4, s4_color)
                draw_label(idx, array.get(s4, idx), 'S4', s4_color, false, true)

            // R4.5 / S4.5
            if r4_5_show
                draw_line(idx, r4_5, r4_5_color, line.style_dashed)
                draw_label(idx, array.get(r4_5, idx), 'R4.5', r4_5_color, false, true)
            if s4_5_show
                draw_line(idx, s4_5, s4_5_color, line.style_dashed)
                draw_label(idx, array.get(s4_5, idx), 'S4.5', s4_5_color, false, true)

            // R5 / S5
            if r5_show
                draw_line(idx, r5, r5_color)
                draw_label(idx, array.get(r5, idx), 'R5', r5_color, false, true)
            if s5_show
                draw_line(idx, s5, s5_color)
                draw_label(idx, array.get(s5, idx), 'S5', s5_color, false, true)


    i = array.size(arr_time) - 2
    if array.size(p) > 0 and cpr_show
        draw_label(i, array.get(p, i), 'CPR', cpr_color, true, false)
    if array.size(tp) > 0 and cpr_show
        draw_label(i, array.get(tp, i), '', cpr_color, true, false)
    if array.size(bp) > 0 and cpr_show
        draw_label(i, array.get(bp, i), '', cpr_color, true, false)

    // --- PDH / PDL limited to the last `look_back` CPR periods (no steplines) ---
    if show_day and array.size(arr_time) > 1 and array.size(pdh_arr) == array.size(p)
        // map style string → line.style_*
        pd_style = session_hl_line_style == 'Solid' ? line.style_solid :
                   session_hl_line_style == 'Dashed' ? line.style_dashed :
                   line.style_dotted

        // draw only for the most-recent `look_back` CPR segments
        start_idx = math.max(0, j - (look_back - 1))
        for k = start_idx to j
            // horizontal segment for PDH between CPR period k start/end
            if not na(array.get(pdh_arr, k))
                line_pdH = line.new(x1 = array.get(arr_time, k),     y1 = array.get(pdh_arr, k),x2 = array.get(arr_time, k + 1), y2 = array.get(pdh_arr, k),xloc = xloc.bar_time, color = session_high_color,width = line_width, style = pd_style)
                array.push(lines, line_pdH)

            // PDH label
            if pd_show_labels or pd_show_prices
                _p  = array.get(pdh_arr, k)
                _x  = position_labels == 'Left' ? array.get(arr_time, k) : array.get(arr_time, k + 1)
                _t  = pd_label_text('PH', _p, pd_show_labels, pd_show_prices)
                if _t != ''
                    array.push(labels, label.new(x = _x, y = _p, xloc = xloc.bar_time,
                                                 text = _t, textcolor = session_high_color,
                                                 style = label.style_none, color = #00000000))




            // horizontal segment for PDL between CPR period k start/end
            if not na(array.get(pdl_arr, k))
                line_pdL = line.new(x1 = array.get(arr_time, k),     y1 = array.get(pdl_arr, k),x2 = array.get(arr_time, k + 1), y2 = array.get(pdl_arr, k),xloc = xloc.bar_time, color = session_low_color,width = line_width, style = pd_style)
                array.push(lines, line_pdL)

            // PDL label
            if pd_show_labels or pd_show_prices
                _p  = array.get(pdl_arr, k)
                _x  = position_labels == 'Left' ? array.get(arr_time, k) : array.get(arr_time, k + 1)
                _t  = pd_label_text('PL', _p, pd_show_labels, pd_show_prices)
                if _t != ''
                    array.push(labels, label.new(x = _x, y = _p, xloc = xloc.bar_time,
                                                 text = _t, textcolor = session_low_color,
                                                 style = label.style_none, color = #00000000))



isHoliday(_date) =>
    is_holiday = _date == timestamp(2024, 12, 25, 15, 30) or _date == timestamp(2025, 02, 26, 15, 30) or _date == timestamp(2025, 03, 14, 15, 30) or _date == timestamp(2025, 03, 31, 15, 30) or _date == timestamp(2025, 04, 10, 15, 30) or _date == timestamp(2025, 04, 14, 15, 30) or _date == timestamp(2025, 04, 18, 15, 30) or _date == timestamp(2025, 05, 01, 15, 30) or _date == timestamp(2025, 08, 15, 15, 30) or _date == timestamp(2025, 08, 27, 15, 30) or _date == timestamp(2025, 10, 02, 15, 30) or _date == timestamp(2025, 10, 21, 15, 30) or _date == timestamp(2025, 10, 22, 15, 30) or _date == timestamp(2025, 11, 05, 15, 30) or _date == timestamp(2025, 12, 25, 15, 30)
    is_holiday

getDevEndTime() =>
    ONE_DAY = 1000 * 60 * 60 * 24
    var dev_end_time = 0
    if resolution == 'D'
        dev_end_time := time_close(resolution) + ONE_DAY
        dev_end_time
    else if resolution == 'W'
        dev_end_time := time_close(resolution) + ONE_DAY * 7
        dev_end_time
    else if resolution == 'M'
        dev_end_time := time_close(resolution) + ONE_DAY * 30
        dev_end_time
    else if resolution == '6M'
        dev_end_time := time_close(resolution) + ONE_DAY * 30 * 6
        dev_end_time
    else
        dev_end_time := time_close(resolution) + ONE_DAY * 30 * 12
        dev_end_time

    while dayofweek(dev_end_time) == dayofweek.saturday or dayofweek(dev_end_time) == dayofweek.sunday or check_holidays and isHoliday(dev_end_time)
        dev_end_time := dev_end_time + ONE_DAY
        dev_end_time

    if extend_dev_cpr_line
        dev_end_time := dev_end_time + ONE_DAY * dev_cpr_line_days
        dev_end_time

    dev_end_time



drawLineAndLabel(_price, _line_color, _text, _text_color, is_dev = false) =>

    labelText = _text
    if is_dev
        if _text == 'Dev R1'
            labelText := 'Dev R1'
        else if _text == 'Dev S1'
            labelText := 'Dev S1'
        else if _text == 'Dev CPR'
            labelText := 'Dev CPR'


    _showLbl = true
    _showPrc = true
    if is_dev
        if _text == 'Dev CPR'
            _showLbl := dev_cpr_show_labels
            _showPrc := dev_cpr_show_prices
        else if _text == 'Dev R1'
            _showLbl := dev_r1_show_labels
            _showPrc := dev_r1_show_prices
        else if _text == 'Dev S1'
            _showLbl := dev_s1_show_labels
            _showPrc := dev_s1_show_prices
        else
            // empty-text Dev CPR edges use Dev CPR toggles
            _showLbl := dev_cpr_show_labels
            _showPrc := dev_cpr_show_prices


    start_time = time_close(resolution)
    end_time   = is_dev ? getDevEndTime() : time_close(resolution)


    _aLine = line.new(x1 = start_time, y1 = _price, x2 = end_time, y2 = _price,
                      xloc = xloc.bar_time, color = _line_color, width = line_width)
    line.delete(_aLine[1])


    if _showLbl or _showPrc
        var string display = ''

        // Special: Dev R1 with % distance
        if is_dev and _text == 'Dev R1' and _showPrc
            pct    = (_price - close) / close * 100
            pctStr = str.tostring(pct, '#.0')
            if _showLbl
                display := str.format('                                {0} - {1} ({2}%)',
                                      labelText, math.round_to_mintick(_price), pctStr)
            else
                display := str.format('                                {0} ({1}%)',
                                      math.round_to_mintick(_price), pctStr)
        else
            // If there is NO label text (top/bottom CPR edges), still show price when enabled
            if labelText == ''
                if _showPrc
                    display := str.format('                                {0}', math.round_to_mintick(_price))
                // else display remains empty (no text and no price)
            else
                // label text exists: combine according to toggles
                if _showLbl and _showPrc
                    display := str.format('                                {0} - {1}',
                                          labelText, math.round_to_mintick(_price))
                else if _showLbl
                    display := '                                ' + labelText
                else if _showPrc
                    display := str.format('                                {0}', math.round_to_mintick(_price))

        if display != ''
            label.new(x = end_time, y = _price, xloc = xloc.bar_time,
                      text = display, textcolor = _line_color, style = label.style_none)

    _aLine


[curr_h, curr_l, curr_c] = request.security(syminfo.tickerid, resolution, [high, low, close], lookahead = barmerge.lookahead_on)

if barstate.islast
    dpp = (curr_h + curr_l + curr_c) / 3.0
    dbc = (curr_h + curr_l) / 2.0
    dtc = dpp * 2 - dbc
    dev_top = dtc > dbc ? dtc : dbc
    dev_bot = dbc < dtc ? dbc : dtc

    if dev_cpr_show
        dtp = drawLineAndLabel(dev_top, dev_cpr_color, '', dev_cpr_color, true)
        drawLineAndLabel(dpp, dev_cpr_color, 'Dev CPR', dev_cpr_color, true)
        dbp = drawLineAndLabel(dev_bot, dev_cpr_color, '', dev_cpr_color, true)
        linefill.new(dtp, dbp, color.new(dev_cpr_color, 70))

    if dev_r1_show
        _dev_r1 = dpp * 2 - curr_l
        if kind == FIBONACCI
            _dev_r1 := dpp + 0.382 * (curr_h - curr_l)
            _dev_r1
        drawLineAndLabel(_dev_r1, dev_r1_color, 'Dev R1', dev_r1_color, true)

    if dev_s1_show
        _dev_s1 = dpp * 2 - curr_h
        if kind == FIBONACCI
            _dev_s1 := dpp - 0.382 * (curr_h - curr_l)
            _dev_s1
        drawLineAndLabel(_dev_s1, dev_s1_color, 'Dev S1', dev_s1_color, true)



// Functions
getAllTimeHigh() =>
    h = 0.0
    h := bar_index == 0 ? high : high > h[1] ? high : h[1]
    h

getAllTimeLow() =>
    l = 0.0
    l := bar_index == 0 ? low : low < l[1] ? low : l[1]
    l

get_resolution() =>
    resolution = 'M'
    if timeframe.isintraday
        resolution := timeframe.multiplier <= 15 ? 'D' : 'W'
        resolution
    else if timeframe.isweekly or timeframe.ismonthly
        resolution := '12M'
        resolution
    resolution

// Session line drawer (no extend)
drawLine(price, _text, lineColor, lineStyle, showLabels, showPrices) =>
    fLineStyle = switch lineStyle
        'Dotted' => line.style_dotted
        'Dashed' => line.style_dashed
        => line.style_solid

    endOfDay = time_tradingday + 105000000
    aLine = line.new(x1 = time_tradingday, y1 = price,x2 = endOfDay,        y2 = price,xloc = xloc.bar_time,color = lineColor,style = fLineStyle)
    line.delete(aLine[1])

    fText = _text
    if showLabels and showPrices
        fText := str.format('{0} - {1}', _text, math.round_to_mintick(price))
    else if showPrices
        fText := str.format('{0}', math.round_to_mintick(price))

    if showLabels or showPrices
        aLabel = label.new(endOfDay, price, xloc=xloc.bar_time,
                           text=str.format('                                {0}', fText),
                           textcolor=lineColor, style=label.style_none)
        label.delete(aLabel[1])


drawOpen(show, resolution, labelText, lineColor, lineStyle, showLabels, showPrices) =>
    _open = request.security(syminfo.tickerid, resolution, open)
    if show
        drawLine(_open, labelText, lineColor, lineStyle, showLabels, showPrices)

drawHighLow(show, resolution, labelTextHigh, labelTextLow, highColor, lowColor, lineStyle, showLabels, showPrices) =>
    [_high, _low] = request.security(syminfo.tickerid, resolution, [high[1], low[1]])
    if show and not na(_high)
        drawLine(_high, labelTextHigh, highColor, lineStyle, showLabels, showPrices)
        drawLine(_low,  labelTextLow,  lowColor,  lineStyle, showLabels, showPrices)




// Session Open
drawOpen(show_day_open, 'D', '     Day Open', session_open_color, session_open_line_style, true, true)

